import './style.css'

class Blackboard {
    // 背景板
    private canvas: HTMLCanvasElement
    private ctx: CanvasRenderingContext2D
    private backgroundColor: string = '#000'

    // 写字板
    private chalkCanvas: HTMLCanvasElement
    private chalkCtx: CanvasRenderingContext2D
    private chalkColor: string = '#fff'

    private width: number
    private height: number

    public constructor(el: string | HTMLElement, width: number = 800, height: number = 400) {
        this.width = width
        this.height = height

        // init canvas
        this.canvas = createCanvas(el, 'canvas', width, height)
        this.chalkCanvas = createCanvas(el, 'chalkCanvas', width, height)

        // init context
        this.ctx = this.canvas.getContext('2d')!
        this.chalkCtx = this.chalkCanvas.getContext('2d')!

        // init properties
        this.init()

        // binding events
        this.bindEvent()
    }

    private init() {
        // 初始化黑板背景色
        this.setBackground()

        // 调整画板位置, 背景设置为透明
        this.chalkCtx.fillStyle = 'transparent'
        this.chalkCtx.fillRect(0, 0, this.getWidth(), this.getHeight())

        // 创建按钮
        this.createBtns()
    }
    private bindEvent() {
        const ctx = this.getContext()
        const canvas = this.getCanvas()
        const onMouseMove = (event: MouseEvent) => this.drawLine(event)
        canvas.addEventListener('mousedown', (event: MouseEvent) => {
            if (event.button !== 0) return // 只有鼠标左键点击才会执行后续代码
            ctx.beginPath()
            canvas.addEventListener('mousemove', onMouseMove)
        })
        document.addEventListener('mouseup', () => canvas.removeEventListener('mousemove', onMouseMove))
    }

    public setBackground(color?: string) {
        const ctx = this.ctx
        ctx.clearRect(0, 0, this.getWidth(), this.getHeight())
        ctx.fillStyle = this.backgroundColor
        if (color) {
            ctx.fillStyle = color
            this.backgroundColor = color
        }
        ctx.fillRect(0, 0, this.getWidth(), this.getHeight())
    }

    public getChalkColor() {
        return this.chalkColor
    }

    public getBackgroundColor() {
        return this.backgroundColor
    }

    public getWidth() {
        return this.width
    }
    public getHeight() {
        return this.height
    }

    // =========== 私有方法 ===========
    private createBtns() {
        const btns = document.createElement('div')
        btns.classList.add('btns')
        this.chalkCanvas.insertAdjacentElement('afterend', btns)
        const createClearBtn = () => {
            const clearBtn = document.createElement('button')
            clearBtn.classList.add('clear-btn')
            clearBtn.id = 'clear-btn'
            clearBtn.type = 'button'
            clearBtn.title = 'clear-btn'
            clearBtn.innerText = '清屏'
            clearBtn.style.cssText = 'display: inline-block; height: 30px; width: 50px'
            btns.appendChild(clearBtn)
            clearBtn.addEventListener('click', () => {
                const ctx = this.getContext()
                ctx.clearRect(0, 0, this.getWidth(), this.getHeight())
            })
        }
        const createChalkColorBtn = () => {
            const colors = ['#1abc9c', '#f1c40f', '#9b59b6', '#ecf0f1']
            colors.forEach((color) => {
                const btn = document.createElement('button')
                btn.classList.add('color-btn')
                btn.type = 'button'
                btn.title = 'color-btn'
                btn.style.cssText = 'display: inline-block; height: 30px; width: 30px'
                btn.style.backgroundColor = color
                btns.appendChild(btn)
                btn.addEventListener('click', () => (this.chalkColor = color))
            })
        }
        createClearBtn()
        createChalkColorBtn()
    }

    private drawLine(event: MouseEvent) {
        const ctx = this.getContext()
        const [x, y] = [event.offsetX, event.offsetY]
        ctx.strokeStyle = this.getChalkColor()
        ctx.lineTo(x, y)
        ctx.stroke()
    }

    private getContext() {
        return this.chalkCtx
    }

    private getCanvas() {
        return this.chalkCanvas
    }
}

const createCanvas = (el: HTMLElement | string, id: string, width: number, height: number) => {
    const canvas = document.createElement('canvas')
    canvas.id = id
    canvas.width = width
    canvas.height = height
    if (typeof el === 'string') {
        document.querySelector(el)?.appendChild(canvas)
    } else {
        el.appendChild(canvas)
    }
    return canvas
}

new Blackboard('#app')
